// check main pointer
owl_bool owl_check_smg_tpt1_main_pointer(owl_byte * src, owl_umax size)
{
  return (src != NULL && size >= sizeof(owl_smg_tpt1_main));
}

// check ext pointer
owl_bool owl_check_smg_tpt1_ext_pointer(owl_byte * src, owl_umax size)
{
  return (src != NULL && size >= sizeof(owl_smg_tpt1_extra));
}

// check pointer
owl_bool owl_check_smg_tpt1_pointer(owl_byte * src, owl_umax size)
{
  return (src != NULL && size >= sizeof(owl_smg_tpt1));
}

// check main members
owl_bool owl_check_smg_tpt1_main_members(owl_byte loop_mode,
                                         owl_umax anim_length,
                                         owl_umax mat_count,
                                         owl_umax tex_indexes_length,
                                         struct owl_smg_tpt1_mat_anim_data_main * mat_anim_data_main,
                                         owl_umax * tex_indexes,
                                         owl_umax * mat_indexes,
                                         owl_smg_name_table * mat_names)
{
  // check params
  if (loop_mode > 4 || anim_length == 0 || tex_indexes_length == 0
      || mat_anim_data_main == NULL || tex_indexes == NULL || mat_indexes == NULL
      || owl_check_smg_name_table_all(mat_names, sizeof(owl_smg_name_table)) == owl_false
      || mat_count != mat_names -> main -> count)
    goto err;
  
  // mat_anim_data checks with tex_indexes_length
  for (owl_umax i = 0; i < mat_count; i++)
    if (mat_anim_data_main[i].index + mat_anim_data_main[i].length > tex_indexes_length)
      goto err;
  
  // done!
  return owl_true;
  err:
  return owl_false;
}

// check main all
owl_bool owl_check_smg_tpt1_main_all(owl_smg_tpt1_main * main, owl_umax size)
{
  return (owl_check_smg_tpt1_main_pointer((void *) main, size) == owl_true
          && owl_check_smg_tpt1_main_members(main -> loop_mode,
                                             main -> anim_length,
                                             main -> mat_count,
                                             main -> tex_indexes_length,
                                             main -> mat_anim_data_main,
                                             main -> tex_indexes,
                                             main -> mat_indexes,
                                             main -> mat_names) == owl_true);
}

// check all
owl_bool owl_check_smg_tpt1_all(owl_smg_tpt1 * tpt1, owl_umax size)
{
  // check params
  if (tpt1 == NULL
      || size < sizeof(owl_smg_tpt1)
      || owl_check_smg_tpt1_main_all(tpt1 -> main, sizeof(owl_smg_tpt1_main)) == owl_false)
    goto err;
  if (tpt1 -> ext == NULL) // this structure section is not strictly required
    return owl_true;
  if (tpt1 -> ext -> mat_anim_data_extra == NULL)
    goto err;
  
  // check all data together
  
  // variables to ease the check
  owl_umax tmp1 = 0, tmp2 = 0;
  
  // magic
  if (tpt1 -> ext -> magic != OWL_SMG_TPT1_MAGIC[0][0]
      && tpt1 -> ext -> magic != OWL_SMG_TPT1_MAGIC[0][1]) goto err;
  // unknown1
  if (tpt1 -> ext -> unknown1 != OWL_SMG_TPT1_UNKNOWN1) goto err;
  // mat_anim_data_offset
  if (tpt1 -> ext -> mat_anim_data_offset != OWL_SMG_TPT1_MAT_ANIM_DATA_OFFSET) goto err;
  tmp1 = 32 + (8 * tpt1 -> main -> mat_count);
  // tex_indexes_offset
  if (tpt1 -> ext -> tex_indexes_offset != tmp1) goto err;
  tmp1 += (2 * tpt1 -> main -> tex_indexes_length);
  // pad1_size
  if ((tmp2 = owl_get_padding_align_4_length(tmp1)) != tpt1 -> ext -> pad1_size) goto err;
  tmp1 += tmp2;
  // mat_indexes_offset
  if (tpt1 -> ext -> mat_indexes_offset != tmp1) goto err;
  tmp1 += (tpt1 -> main -> mat_count * 2);
  // pad2_size
  if ((tmp2 = owl_get_padding_align_4_length(tmp1)) != tpt1 -> ext -> pad2_size) goto err;
  tmp1 += tmp2;
  // mat_names_offset
  if (tpt1 -> ext -> mat_names_offset != tmp1) goto err;
  tmp1 += owl_get_smg_name_table_bin_size(tpt1 -> main -> mat_names);
  // pad3_size
  if ((tmp2 = owl_get_padding_align_32_length(tmp1)) != tpt1 -> ext -> pad3_size) goto err;
  tmp1 += tmp2;
  // size
  if (tpt1 -> ext -> size != tmp1) goto err;
  
  // mat_anim_data_extra
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++)
    if ((tpt1 -> ext -> mat_anim_data_extra)[i].unknown2 != OWL_SMG_TPT1_UNKNOWN2)
      goto err;
  
  // done!
  return owl_true;
  err:
  return owl_false;
}

// create
owl_smg_tpt1 * owl_create_smg_tpt1(owl_str * raw, owl_endian endian)
{
  // check params
  owl_smg_tpt1 * new = NULL;
  owl_mem_space * tmp_sp = NULL;
  OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_ALL_GOOD;
  OWL_SMG_TPT1_ERR_READ_POS = 0;
  if (owl_check_str_all(raw, sizeof(owl_str)) == owl_false
      || owl_check_endian(endian) == owl_false)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_FUNC_PARAMS; goto err;}
  
  // fill new while checking it
  tmp_sp = owl_create_mem_space(sizeof(owl_smg_tpt1));
  if (tmp_sp == NULL) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MEM_ALLOC; goto err;}
  new = (void *) tmp_sp -> ptr;
  tmp_sp = owl_create_mem_space(sizeof(owl_smg_tpt1_main));
  if (tmp_sp == NULL) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MEM_ALLOC; goto err;}
  new -> main = (void *) tmp_sp -> ptr;
  tmp_sp = owl_create_mem_space(sizeof(owl_smg_tpt1_extra));
  if (tmp_sp == NULL) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MEM_ALLOC; goto err;}
  new -> ext = (void *) tmp_sp -> ptr;
  
  // variables to help read raw
  owl_bitarr bits = {&((owl_mem_space) {raw -> arr -> ptr, raw -> arr -> size}), 0, 0};
  owl_umax tmp = 0;
  
  // section header magic and size and endian detection
  if (bits.arr -> size < 8) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  new -> ext -> magic = owl_get_std_uint32_mw(&bits, OWL_ENDIAN_BIG).integer.u;
  if (new -> ext -> magic != OWL_SMG_TPT1_MAGIC[0][endian == OWL_ENDIAN_BIG ? 0 : 1])
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MAGIC_1; goto err;}
  new -> ext -> size = owl_get_std_uint32_mw(&bits, endian).integer.u;
  if (new -> ext -> size % 32 != 0 || new -> ext -> size == 0 || new -> ext -> size > raw -> arr -> size)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_SIZE_1; goto err;}
  bits.arr -> size = new -> ext -> size - 8; // assign the new size and keep the check with that
  
  // loop mode, unknown 1, animation length, material count, tex swap table length
  if (bits.arr -> size < 8) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;} 
  new -> main -> loop_mode = owl_get_std_uint8_mw(&bits, endian).integer.u;
  if (new -> main -> loop_mode > 4)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_LOOP_MODE_1; goto err;}
  new -> ext -> unknown1 = owl_get_std_uint8_mw(&bits, endian).integer.u;
  if (new -> ext -> unknown1 != OWL_SMG_TPT1_UNKNOWN1)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_UNKNOWN1_1; goto err;}
  new -> main -> anim_length = owl_get_std_uint16_mw(&bits, endian).integer.u;        // can be anything
  new -> main -> mat_count = owl_get_std_uint16_mw(&bits, endian).integer.u;          // can be anything
  new -> main -> tex_indexes_length = owl_get_std_uint16_mw(&bits, endian).integer.u; // can be anything
  
  // mat anim data, tex indexes, mat indexes, mat names offsets
  if (bits.arr -> size < 16) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  new -> ext -> mat_anim_data_offset = owl_get_std_uint32_mw(&bits, endian).integer.u;
  if (new -> ext -> mat_anim_data_offset != OWL_SMG_TPT1_MAT_ANIM_DATA_OFFSET)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_TPT1_OFFSET_1; goto err;}
  new -> ext -> tex_indexes_offset = owl_get_std_uint32_mw(&bits, endian).integer.u;
  if (new -> ext -> tex_indexes_offset != (new -> main -> mat_count * 8) + 0x20)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_TEX_INDEXES_OFFSET_1; goto err;}
  new -> ext -> mat_indexes_offset = owl_get_std_uint32_mw(&bits, endian).integer.u;
  tmp = new -> ext -> tex_indexes_offset + (new -> main -> tex_indexes_length * 2);
  tmp = tmp + owl_get_padding_align_4_length(tmp);
  if (new -> ext -> mat_indexes_offset != tmp)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MAT_INDEXES_OFFSET_1; goto err;}
  new -> ext -> mat_names_offset = owl_get_std_uint32_mw(&bits, endian).integer.u;
  tmp = tmp + (2 * new -> main -> mat_count);
  tmp = tmp + owl_get_padding_align_4_length(tmp);
  if (new -> ext -> mat_names_offset != tmp)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MAT_NAMES_OFFSET_1; goto err;}
  
  // material animation data
  if (bits.arr -> size < new -> main -> mat_count * 8)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  tmp_sp = owl_create_mem_space(new -> main -> mat_count * sizeof(struct owl_smg_tpt1_mat_anim_data_main));
  if (tmp_sp == NULL) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MEM_ALLOC; goto err;}
  new -> main -> mat_anim_data_main = (void *) tmp_sp -> ptr;
  tmp_sp = owl_create_mem_space(new -> main -> mat_count * sizeof(struct owl_smg_tpt1_mat_anim_data_extra));
  if (tmp_sp == NULL) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MEM_ALLOC; goto err;}
  new -> ext -> mat_anim_data_extra = (void *) tmp_sp -> ptr;
  for (owl_umax i = 0; i < new -> main -> mat_count; i++) {
    // length
    tmp = owl_get_std_uint16_mw(&bits, endian).integer.u;
    if (tmp > new -> main -> tex_indexes_length || tmp == 0) // == 0 might be able to be used
      {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MAT_ANIM_LENGTH_1; goto err;}
    (new -> main -> mat_anim_data_main)[i].length = tmp;
    // index
    tmp = owl_get_std_uint16_mw(&bits, endian).integer.u;
    if (tmp + (new -> main -> mat_anim_data_main)[i].length > new -> main -> tex_indexes_length)
      {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MAT_ANIM_INDEX_1; goto err;}
    (new -> main -> mat_anim_data_main)[i].index = tmp;
    // unknown 2
    tmp = owl_get_std_uint32_mw(&bits, OWL_ENDIAN_BIG).integer.u;
    if (tmp != OWL_SMG_TPT1_UNKNOWN2)
      {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MAT_ANIM_UNKNOWN2_1; goto err;}
    (new -> ext -> mat_anim_data_extra)[i].unknown2 = tmp;
  }
  
  // tex indexes (can be any value ngl), store them all and go to padding 1
  if (bits.arr -> size < new -> main -> tex_indexes_length * 2)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  tmp_sp = owl_create_mem_space(new -> main -> tex_indexes_length * sizeof(owl_umax));
  if (tmp_sp == NULL) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MEM_ALLOC; goto err;}
  new -> main -> tex_indexes = (void *) tmp_sp -> ptr;
  for (owl_umax i = 0; i < new -> main -> tex_indexes_length; i++)
    (new -> main -> tex_indexes)[i] = owl_get_std_uint16_mw(&bits, endian).integer.u;

  // padding 1 (can be anything)
  tmp = owl_get_padding_align_4_length(bits.arr -> ptr - raw -> arr -> ptr);
  if (bits.arr -> size < tmp) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  new -> ext -> pad1_size = tmp;
  bits.arr -> ptr += tmp;
  bits.arr -> size -= tmp;
  
  // mat indexes (can be anything), store them all and go to padding 2
  if (bits.arr -> size < new -> main -> mat_count * 2)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  tmp_sp = owl_create_mem_space(new -> main -> mat_count * sizeof(owl_umax));
  if (tmp_sp == NULL) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MEM_ALLOC; goto err;}
  new -> main -> mat_indexes = (void *) tmp_sp -> ptr;
  for (owl_umax i = 0; i < new -> main -> mat_count; i++)
    (new -> main -> mat_indexes)[i] = owl_get_std_uint16_mw(&bits, endian).integer.u;
  
  // padding 2 (can be anything)
  tmp = owl_get_padding_align_4_length(bits.arr -> ptr - raw -> arr -> ptr);
  if (bits.arr -> size < tmp) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  new -> ext -> pad2_size = tmp;
  bits.arr -> ptr += tmp;
  bits.arr -> size -= tmp;
  
  // mat names
  owl_str tmp_str = *raw;
  tmp_str.arr = &((owl_mem_space) {bits.arr -> ptr, bits.arr -> size});
  new -> main -> mat_names = owl_create_smg_name_table(&tmp_str, endian);
  if (new -> main -> mat_names == NULL || new -> main -> mat_names -> main -> count != new -> main -> mat_count)
    {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_MAT_NAMES_1; goto err;}
  tmp = owl_get_smg_name_table_bin_size(new -> main -> mat_names);
  bits.arr -> ptr += tmp;
  bits.arr -> size -= tmp;
  
  // padding 3 (can be anything)
  tmp = owl_get_padding_align_32_length(bits.arr -> ptr - raw -> arr -> ptr);
  if (bits.arr -> size < tmp) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  new -> ext -> pad3_size = tmp;
  bits.arr -> ptr += tmp;
  bits.arr -> size -= tmp;

  // incredible last check
  if (bits.arr -> size != 0) {OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_STR_SIZE; goto err;}
  
  // done!
  return new;
  err: // something bad happened
  OWL_SMG_TPT1_ERR_READ_POS = bits.arr -> ptr - raw -> arr -> ptr;
  if (new != NULL) {
    if (new -> main != NULL) {
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main -> mat_anim_data_main, 1}));
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main -> tex_indexes, 1}));
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main -> mat_indexes, 1}));
      owl_free_smg_name_table(new -> main -> mat_names);
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main, 1}));
    }
    if (new -> ext != NULL) {
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> ext -> mat_anim_data_extra, 1}));
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> ext, 1}));
    }
    owl_free_mem_space(&((owl_mem_space) {(void *) new, 1}));
    owl_free_mem_space(tmp_sp);
  }
  return NULL;
}

// free
owl_umax owl_free_smg_tpt1(owl_smg_tpt1 * tpt1)
{
  // check params
  if (owl_check_smg_tpt1_all(tpt1, sizeof(owl_smg_tpt1)) == owl_false)
    goto err;
  
  // free the memory used by each structure component
  
  // main
  owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> main -> mat_anim_data_main, 1}));
  owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> main -> tex_indexes, 1}));
  owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> main -> mat_indexes, 1}));
  owl_free_smg_name_table(tpt1 -> main -> mat_names);
  owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> main, 1}));
  // ext
  if (tpt1 -> ext != NULL) {
    owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> ext -> mat_anim_data_extra, 1}));
    owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> ext, 1}));
  }
  
  // the structure itself
  return owl_free_mem_space(&((owl_mem_space) {(void *) tpt1, 1}));
  err:
  return 0;
}

// print
owl_umax owl_print_smg_tpt1(owl_byte * src, owl_umax size)
{
  // check params
  printf("OWL_SMG_TPT1 struct info:\n");
  printf("  Struct info: %p, %llu\n", src, size);
  if (owl_check_smg_tpt1_all((void *) src, size) == owl_false)
    return 0;
  
  // else print the structure
  owl_smg_tpt1 * tpt1 = (void *) src;
  
  // main
  printf("  OWL_SMG_TPT1_MAIN struct info:\n");
  printf("    Struct info: %p, %lu\n", tpt1 -> main, sizeof(owl_smg_tpt1_main));
  printf("    Loop Mode: %u\n", tpt1 -> main -> loop_mode);
  printf("    Animation length (frames): %llu\n", tpt1 -> main -> anim_length);
  printf("    Material count: %llu\n", tpt1 -> main -> mat_count);
  printf("    Texture indexes length: %llu\n", tpt1 -> main -> tex_indexes_length);
  printf("    Material main animation data: length, index\n");
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++)
    printf("      Mat[%llu]: %llu, %llu\n", i, (tpt1 -> main -> mat_anim_data_main)[i].length,
                                               (tpt1 -> main -> mat_anim_data_main)[i].index);
  printf("    Texture indexes (size = %llu): ", tpt1 -> main -> tex_indexes_length);
  for (owl_umax i = 0; i < tpt1 -> main -> tex_indexes_length; i++) {
    for (owl_umax j = 0; j < tpt1 -> main -> mat_count; j++)
      if (i == (tpt1 -> main -> mat_anim_data_main)[j].index) {printf("| "); break;}
    printf("%llu ", (tpt1 -> main -> tex_indexes)[i]);
  }
  printf("\n    Material indexes: ");
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++)
    printf("%llu ", (tpt1 -> main -> mat_indexes)[i]);
  printf("\n    Material names (shift_jis): size, name\n");
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++) {
    printf("      Mat[%llu]: %llu, ", i, (tpt1 -> main -> mat_names -> main -> names)[i] -> arr -> size);
    for (owl_umax j = 0; j < (tpt1 -> main -> mat_names -> main -> names)[i] -> arr -> size; putchar(' '))
      j += (tpt1 -> main -> mat_names -> main -> names)[i]
           -> print_wchar_enc((tpt1 -> main -> mat_names -> main -> names)[i] -> arr -> ptr + j,
                              (tpt1 -> main -> mat_names -> main -> names)[i] -> arr -> size);
    putchar('\n');
  }
  
  // extra
  if (tpt1 -> ext == NULL) goto end;
  printf("  OWL_SMG_TPT1_EXTRA struct info:\n");
  printf("    Struct info: %p, %lu\n", tpt1 -> ext, sizeof(owl_smg_tpt1_extra));
  printf("    Section magic: %08llX\n", tpt1 -> ext -> magic);
  printf("    Section size (bytes): %llu\n", tpt1 -> ext -> size);
  printf("    Unknown 1 (hex): %02X\n", tpt1 -> ext -> unknown1);
  printf("    Material animation data offset (hex): %08llX\n", tpt1 -> ext -> mat_anim_data_offset);
  printf("    Texture indexes offset (hex): %08llX\n", tpt1 -> ext -> tex_indexes_offset);
  printf("    Material indexes offset (hex): %08llX\n", tpt1 -> ext -> mat_indexes_offset);
  printf("    Material names offset (hex): %08llX\n", tpt1 -> ext -> mat_names_offset);
  printf("    Material extra animation data: unknown 2\n");
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++)
    printf("      Mat[%llu]: 0x%08llX\n", i, (tpt1 -> ext -> mat_anim_data_extra)[i].unknown2);
  printf("    Padding 1 size (bytes): %u\n", tpt1 -> ext -> pad1_size);
  printf("    Padding 2 size (bytes): %u\n", tpt1 -> ext -> pad2_size);
  printf("    Padding 3 size (bytes): %u\n", tpt1 -> ext -> pad3_size);
  
  // done!
  end:
  return sizeof(owl_smg_tpt1);
}

// compare (later)
owl_char owl_comp_smg_tpt1(owl_byte * tpt11, owl_byte * tpt12)
{
  return owl_comp_err;
}

// append the extra information of a tpt1 section
owl_bool owl_get_smg_tpt1_extra(owl_smg_tpt1 * tpt1)
{
  // check params
  owl_mem_space * sp = NULL;
  if (owl_check_smg_tpt1_all(tpt1, sizeof(owl_smg_tpt1)) == owl_false
      || tpt1 -> ext != NULL) return owl_false;
  
  // get it done
  sp = owl_create_mem_space(sizeof(owl_smg_tpt1_extra));
  if (sp == NULL) goto err;
  tpt1 -> ext = (void *) sp -> ptr;
  
  // magic
  owl_umax tmp = 32; // related to size
  tpt1 -> ext -> magic = OWL_SMG_TPT1_MAGIC[0][0]; // magic (big endian)
  tpt1 -> ext -> unknown1 = OWL_SMG_TPT1_UNKNOWN1; // unknown 1
  tpt1 -> ext -> mat_anim_data_offset = OWL_SMG_TPT1_MAT_ANIM_DATA_OFFSET; // mat anim data offset
  tmp += tpt1 -> main -> mat_count * 8;
  tpt1 -> ext -> tex_indexes_offset = tmp; // tex indexes offset
  tmp += tpt1 -> main -> tex_indexes_length * 2;
  tmp += (tpt1 -> ext -> pad1_size = owl_get_padding_align_4_length(tmp)); // pad1 length
  tpt1 -> ext -> mat_indexes_offset = tmp; // mat indexes offset
  tmp += tpt1 -> main -> mat_count * 2;
  tmp += (tpt1 -> ext -> pad2_size = owl_get_padding_align_4_length(tmp)); // pad2 length
  tpt1 -> ext -> mat_names_offset = tmp; // mat names offset
  tmp += owl_get_smg_name_table_bin_size(tpt1 -> main -> mat_names);
  tmp += (tpt1 -> ext -> pad3_size = owl_get_padding_align_32_length(tmp)); // pad3 length
  tpt1 -> ext -> size = tmp; // size  
  
  // mat_anim_data_extra
  sp = owl_create_mem_space(sizeof(struct owl_smg_tpt1_mat_anim_data_extra) * tpt1 -> main -> mat_count);
  if (sp == NULL) goto err;
  tpt1 -> ext -> mat_anim_data_extra = (void *) sp -> ptr;
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++)
    (tpt1 -> ext -> mat_anim_data_extra)[i].unknown2 = OWL_SMG_TPT1_UNKNOWN2;
  
  // done!
  return owl_true;
  err:
  if (tpt1 -> ext != NULL) {
    owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> ext -> mat_anim_data_extra, 1}));
    owl_free_mem_space(&((owl_mem_space) {(void *) tpt1 -> ext, 1}));
  }
  owl_free_mem_space(sp);
  return owl_false;
}

// get the byte size of an encoded tpt1 structure
owl_umax owl_get_smg_tpt1_bin_size(owl_smg_tpt1 * tpt1)
{
  // check params
  if (owl_check_smg_tpt1_all((void *) tpt1, sizeof(owl_smg_tpt1)) == owl_false)
    return 0;
  // lol
  if (tpt1 -> ext != NULL)
    return tpt1 -> ext -> size;
  // calculate the size by getting the extra section
  if (owl_get_smg_tpt1_extra(tpt1) == owl_false)
    return 0;
  return tpt1 -> ext -> size;
}

// get the error code of a tpt1 string
owl_smg_tpt1_err_cd owl_get_err_cd_smg_tpt1(owl_str * raw, owl_endian endian)
{
  // reuse owl_create_smg_tpt1()
  owl_smg_tpt1 * tmp = owl_create_smg_tpt1(raw, endian);
  owl_free_smg_tpt1(tmp);
  return OWL_SMG_TPT1_ERR_CD;
}

// create a smg_tpt1 structure from minimal arguments
owl_smg_tpt1 * owl_get_smg_tpt1_min_args(owl_byte loop_mode,
                                         owl_umax anim_length,
                                         owl_umax mat_count,
                                         owl_umax tex_indexes_length,
                                         struct owl_smg_tpt1_mat_anim_data_main * mat_anim_data_main,
                                         owl_umax * tex_indexes,
                                         owl_umax * mat_indexes,
                                         owl_str ** mat_names)
{
  // check params
  owl_mem_space * sp = NULL;
  owl_smg_tpt1 * new = NULL;
  owl_smg_tpt1_main test = {loop_mode, anim_length, mat_count,
                            tex_indexes_length, mat_anim_data_main, tex_indexes,
                            mat_indexes, owl_get_smg_name_table_min_args(mat_count, mat_names)};
  if (test.mat_names == NULL || owl_check_smg_tpt1_main_all(&test, sizeof(owl_smg_tpt1_main)) == owl_false)
    goto err;
  
  // allocate space
  sp = owl_create_mem_space(sizeof(owl_smg_tpt1));
  if (sp == NULL) goto err;
  new = (void *) sp -> ptr; // structure
  sp = owl_create_mem_space(sizeof(owl_smg_tpt1_main));
  if (sp == NULL) goto err;
  new -> main = (void *) sp -> ptr; // main
  sp = owl_create_mem_space(sizeof(struct owl_smg_tpt1_mat_anim_data_main) * mat_count);
  if (sp == NULL) goto err;
  new -> main -> mat_anim_data_main = (void *) sp -> ptr; // mat_anim_data_main
  sp = owl_create_mem_space(sizeof(owl_umax) * tex_indexes_length);
  if (sp == NULL) goto err;
  new -> main -> tex_indexes = (void *) sp -> ptr; // tex_indexes
  sp = owl_create_mem_space(sizeof(owl_umax) * mat_count);
  if (sp == NULL) goto err;
  new -> main -> mat_indexes = (void *) sp -> ptr; // mat_indexes
  
  // data
  new -> main -> loop_mode = loop_mode;
  new -> main -> anim_length = anim_length;
  new -> main -> mat_count = mat_count;
  new -> main -> tex_indexes_length = tex_indexes_length;
  for (owl_umax i = 0; i < mat_count; i++) {
    (new -> main -> mat_anim_data_main)[i].index = (mat_anim_data_main)[i].index;
    (new -> main -> mat_anim_data_main)[i].length = (mat_anim_data_main)[i].length;
    (new -> main -> mat_indexes)[i] = mat_indexes[i];
  }
  for (owl_umax i = 0; i < tex_indexes_length; i++)
    (new -> main -> tex_indexes)[i] = tex_indexes[i];
  new -> main -> mat_names = test.mat_names;
  
  // done!
  return new;
  err:
  if (new != NULL) {
    if (new -> main != NULL) {
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main -> mat_anim_data_main, 1}));
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main -> tex_indexes, 1}));
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main -> mat_indexes, 1}));
      owl_free_smg_name_table(new -> main -> mat_names);
      owl_free_mem_space(&((owl_mem_space) {(void *) new -> main, 1}));
    }
    owl_free_mem_space(&((owl_mem_space) {(void *) new, 1}));
  }
  owl_free_mem_space(sp);
  return NULL;
}

// create a smg tpt1 string
owl_str * owl_get_smg_tpt1_as_str(owl_smg_tpt1 * tpt1, owl_endian endian)
{
  // check params
  owl_mem_space * sp = NULL;
  owl_str * new = NULL, * tmp = NULL;
  if (owl_check_smg_tpt1_all(tpt1, sizeof(owl_smg_tpt1)) == owl_false
      || owl_check_endian(endian) == owl_false) goto err;
  
  // create the extra section if not there
  if (tpt1 -> ext == NULL && owl_get_smg_tpt1_extra(tpt1) == owl_false)
    goto err;
  
  // allocate space for the encoded tpt1
  sp = owl_create_mem_space(tpt1 -> ext -> size);
  if (sp == NULL) goto err;
  
  // write data
  owl_bitarr write = {&((owl_bytarr) {sp -> ptr, sp -> size}), 0, 0};
  
  // magic and size
  if (owl_write_std_uint32_mv(OWL_SMG_TPT1_MAGIC[0][0], &write, endian) == owl_false) goto err;
  if (owl_write_std_uint32_mv(tpt1 -> ext -> size, &write, endian) == owl_false) goto err;  
  // loop_mode and unknown1
  if (owl_write_std_uint8_mv(tpt1 -> main -> loop_mode, &write, endian) == owl_false) goto err;
  if (owl_write_std_uint8_mv(tpt1 -> ext -> unknown1, &write, endian) == owl_false) goto err;
  // anim_length, mat_count and tex_indexes_length
  if (owl_write_std_uint16_mv(tpt1 -> main -> anim_length, &write, endian) == owl_false) goto err;
  if (owl_write_std_uint16_mv(tpt1 -> main -> mat_count, &write, endian) == owl_false) goto err;
  if (owl_write_std_uint16_mv(tpt1 -> main -> tex_indexes_length, &write, endian) == owl_false) goto err;
  // offsets
  if (owl_write_std_uint32_mv(tpt1 -> ext -> mat_anim_data_offset, &write, endian) == owl_false) goto err;
  if (owl_write_std_uint32_mv(tpt1 -> ext -> tex_indexes_offset, &write, endian) == owl_false) goto err;
  if (owl_write_std_uint32_mv(tpt1 -> ext -> mat_indexes_offset, &write, endian) == owl_false) goto err;
  if (owl_write_std_uint32_mv(tpt1 -> ext -> mat_names_offset, &write, endian) == owl_false) goto err;
  // mat_anim_data
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++) {
    // length, index and unknown2
    if (owl_write_std_uint16_mv((tpt1 -> main -> mat_anim_data_main)[i].length, &write, endian) == owl_false) goto err;
    if (owl_write_std_uint16_mv((tpt1 -> main -> mat_anim_data_main)[i].index, &write, endian) == owl_false) goto err;    
    if (owl_write_std_uint32_mv((tpt1 -> ext -> mat_anim_data_extra)[i].unknown2, &write, OWL_ENDIAN_BIG) == owl_false) goto err;
  }
  // tex_indexes
  for (owl_umax i = 0; i < tpt1 -> main -> tex_indexes_length; i++)
    if (owl_write_std_uint16_mv((tpt1 -> main -> tex_indexes)[i], &write, endian) == owl_false) goto err;
  // pad1
  if (tpt1 -> ext -> pad1_size != 0)
    *(write.arr) = owl_copy_bytarr(&((owl_bytarr) {OWL_SMG_PAD_STR.arr -> ptr, tpt1 -> ext -> pad1_size}), write.arr);
  // mat_indexes
  for (owl_umax i = 0; i < tpt1 -> main -> mat_count; i++)
    if (owl_write_std_uint16_mv((tpt1 -> main -> mat_indexes)[i], &write, endian) == owl_false) goto err;
  // pad2
  if (tpt1 -> ext -> pad2_size != 0)
    *(write.arr) = owl_copy_bytarr(&((owl_bytarr) {OWL_SMG_PAD_STR.arr -> ptr, tpt1 -> ext -> pad2_size}), write.arr);
  // mat_names
  tmp = owl_get_smg_name_table_as_str(tpt1 -> main -> mat_names, endian);
  if (tmp == NULL) goto err;
  owl_copy_bytarr(tmp -> arr, &((owl_bytarr) {write.arr -> ptr, tmp -> arr -> size}));
  write.arr = &((owl_bytarr) {write.arr -> ptr + tmp -> arr -> size,
                              write.arr -> size - tmp -> arr -> size});
  owl_free_str(tmp);
  // pad3
  if (tpt1 -> ext -> pad3_size != 0)
    *(write.arr) = owl_copy_bytarr(&((owl_bytarr) {OWL_SMG_PAD_STR.arr -> ptr, tpt1 -> ext -> pad3_size}), write.arr);
  
  // copy sp into new and return new
  new = owl_create_str(sp -> ptr, sp -> size, OWL_WCHAR_ENC_BIN);
  if (new == NULL) goto err;
  owl_free_mem_space(sp);
  
  // done!
  return new;
  err:
  owl_free_mem_space(sp);
  owl_free_str(tmp);
  owl_free_str(new);
  return NULL;
}
